package com.niiwoo.civet.trade.service.local.notify;

import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.trade.enums.NotifyTypeEnum;
import com.niiwoo.civet.user.dto.request.UserLetterRequestDTO;
import com.niiwoo.civet.user.enums.SMSTemplateKeyEnum;
import com.niiwoo.civet.user.service.SendSmsDubboService;
import com.niiwoo.civet.user.service.UserLetterDubboService;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public abstract class AbstractNotifier<T> {

    private static final Logger log = LoggerFactory.getLogger(AbstractNotifier.class);
    private static final int STEP = 10;
    private SendSmsDubboService sendSmsDubboService;
    private UserLetterDubboService userLetterDubboService;

    public <U extends T> void notifyUser(U t) {
        List<? extends UserNotifyInfo> notifyUsers = this.getUserNotifyInfoList(t);
        if (notifyUsers == null || notifyUsers.isEmpty()) {
            return;
        }
        int bound = notifyUsers.size();
        int times = bound / STEP + (bound % STEP == 0 ? 0 : 1);
        int fromIndex;
        int toIndex;
        // 每10个通知一个任务
        for (int i = 0; i < times; i++) {
            fromIndex = i * STEP;
            toIndex = Math.min(fromIndex + STEP, bound);
            notifyInBatch(notifyUsers.subList(fromIndex, toIndex));
        }
    }

    private void notifyInBatch(List<? extends UserNotifyInfo> notifyUsers) {
        String traceId = MDC.get("traceId");
        CompletableFuture.runAsync(() -> {
            MDC.getMDCAdapter().put("traceId", traceId);
            notifyUsers.forEach(info -> {
                // 站内信和极光推送
                Optional.ofNullable(this.getUserLetterRequestDTO(info)).ifPresent(letterRequest -> {
                    log.info("消息通知###{}推送###请求, data={}", this.getType().name(), JSON.toJSONString(letterRequest));
                    try {
                        userLetterDubboService.pushLetter(letterRequest);
                    } catch (Exception e) {
                        log.error(String.format("消息通知###%s推送###异常, errorMessage=%s", this.getType().name(), e.getMessage()), e);
                    }
                });
                // 优先使用手机号码发送
                Optional.ofNullable(this.getSMSRequestDTO(info))
                        .ifPresent(smsRequest -> {
                            Consumer<SMSRequest> c;
                            if (StringUtils.isNotBlank(smsRequest.getMobileNo())) {
                                c = r -> sendSmsDubboService.sendSmsByMobile(r.getMobileNo(), r.getSmsTemplateKeyEnum().getKey(), r.getParamList());
                                // 否则使用userId发送
                            } else {
                                c = r -> sendSmsDubboService.sendSmsByUserId(r.getUserId(), r.getSmsTemplateKeyEnum().getKey(), r.getParamList());
                            }
                            try {
                                log.info("消息通知###{}短信###请求, data={}", this.getType().name(), JSON.toJSONString(smsRequest));
                                c.accept(smsRequest);
                            } catch (Exception e) {
                                log.error(String.format("消息通知###%s短信###异常, errorMessage=%s", this.getType().name(), e.getMessage()), e);
                            }
                        });
            });
        });
    }

    abstract protected List<? extends UserNotifyInfo> getUserNotifyInfoList(T t);

    abstract protected UserLetterRequestDTO getUserLetterRequestDTO(UserNotifyInfo info);

    protected SMSRequest getSMSRequestDTO(UserNotifyInfo info) {
        return null;
    }

    abstract protected NotifyTypeEnum getType();

    public void setSendSmsDubboService(SendSmsDubboService sendSmsDubboService) {
        this.sendSmsDubboService = sendSmsDubboService;
    }

    public void setUserLetterDubboService(UserLetterDubboService userLetterDubboService) {
        this.userLetterDubboService = userLetterDubboService;
    }

    public abstract static class UserNotifyInfo {

    }

    @Getter
    @Setter
    public static class SMSRequest {

        private String mobileNo;

        private String userId;

        private SMSTemplateKeyEnum smsTemplateKeyEnum;

        private List<Object> paramList;

    }

}
